package com.wzb.mybatisplus.bitaction.formal;

import org.bouncycastle.asn1.sec.SECNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.math.ec.ECPoint;

import java.math.BigInteger;
import java.security.MessageDigest;
import java.util.Scanner;

public class BitcoinPrivateKeyFromInput {

    // secp256k1 曲线参数
    private static final X9ECParameters CURVE_PARAMS = SECNamedCurves.getByName("secp256k1");
    private static final BigInteger CURVE_ORDER = CURVE_PARAMS.getN();

    // 私钥最大值 (n - 1)
    private static final BigInteger MAX_PRIVATE_KEY = CURVE_ORDER.subtract(BigInteger.ONE);

    public static void main(String[] args) throws Exception {
        Scanner scanner = new Scanner(System.in);

        System.out.println("=== 比特币主网私钥生成器 ===");
        System.out.println("私钥有效范围: 1 到 " + MAX_PRIVATE_KEY.toString(16).toUpperCase());

        while (true) {
            System.out.println("\n请选择输入格式:");
            System.out.println("1. 十六进制 (Hex)");
            System.out.println("2. 十进制 (Decimal)");
            System.out.println("3. 退出");
            System.out.print("请选择 (1-3): ");

            String choice = scanner.nextLine().trim();

            switch (choice) {
                case "1":
                    processHexInput(scanner);
                    break;
                case "2":
                    processDecimalInput(scanner);
                    break;
                case "3":
                    System.out.println("程序退出");
                    scanner.close();
                    return;
                default:
                    System.out.println("无效选择，请重新输入");
            }
        }
    }

    /**
     * 处理十六进制输入
     */
    private static void processHexInput(Scanner scanner) throws Exception {
        System.out.print("请输入私钥 (十六进制): ");
        String hexInput = scanner.nextLine().trim();

        // 移除可能的前缀和空格
        hexInput = hexInput.replace("0x", "").replace(" ", "");

        if (hexInput.isEmpty()) {
            System.out.println("输入不能为空");
            return;
        }

        try {
            BigInteger privateKey = new BigInteger(hexInput, 16);
            processPrivateKey(privateKey, "十六进制: " + hexInput);
        } catch (NumberFormatException e) {
            System.out.println("无效的十六进制格式");
        }
    }

    /**
     * 处理十进制输入
     */
    private static void processDecimalInput(Scanner scanner) throws Exception {
        System.out.print("请输入私钥 (十进制): ");
        String decimalInput = scanner.nextLine().trim();

        if (decimalInput.isEmpty()) {
            System.out.println("输入不能为空");
            return;
        }

        try {
            BigInteger privateKey = new BigInteger(decimalInput);
            processPrivateKey(privateKey, "十进制: " + decimalInput);
        } catch (NumberFormatException e) {
            System.out.println("无效的数字格式");
        }
    }

    /**
     * 处理私钥并生成WIF格式
     */
    private static void processPrivateKey(BigInteger privateKey, String inputInfo) throws Exception {
        System.out.println("\n输入信息: " + inputInfo);

        // 验证私钥范围
        if (privateKey.compareTo(BigInteger.ONE) < 0) {
            System.out.println("错误: 私钥必须大于 0");
            return;
        }

        if (privateKey.compareTo(MAX_PRIVATE_KEY) > 0) {
            System.out.println("错误: 私钥超过最大值");
            System.out.println("最大值: " + MAX_PRIVATE_KEY.toString(16).toUpperCase());
            return;
        }

        // 显示私钥信息
        System.out.println("私钥 (十六进制): " + privateKey.toString(16).toUpperCase());
        System.out.println("私钥 (十进制): " + privateKey.toString());

        // 检查当前私钥对应的WIF格式
        boolean isCurrentlyK = isKStart(privateKey);
        char currentPrefix = isCurrentlyK ? 'K' : 'L';
        System.out.println("当前私钥对应WIF开头: " + currentPrefix);

        // 生成当前格式的WIF
        String currentWIF = privateKeyToWIF(privateKey, true);
        System.out.println("当前WIF格式: " + currentWIF);

        // 询问是否需要转换格式
        Scanner scanner = new Scanner(System.in);
        System.out.print("\n是否要转换格式? (y/N): ");
        String convertChoice = scanner.nextLine().trim().toLowerCase();

        if (convertChoice.equals("y") || convertChoice.equals("yes")) {
            System.out.print("想要哪种格式? (K/L): ");
            String formatChoice = scanner.nextLine().trim().toUpperCase();

            if (formatChoice.equals("K") || formatChoice.equals("L")) {
                boolean wantK = formatChoice.equals("K");

                if ((wantK && !isCurrentlyK) || (!wantK && isCurrentlyK)) {
                    // 需要转换格式，通过调整私钥实现
                    BigInteger adjustedKey = adjustPrivateKeyFormat(privateKey, wantK);
                    if (adjustedKey != null) {
                        String adjustedWIF = privateKeyToWIF(adjustedKey, true);
                        System.out.println("\n转换后的WIF: " + adjustedWIF);
                        System.out.println("新私钥 (十六进制): " + adjustedKey.toString(16).toUpperCase());
                        System.out.println("新私钥 (十进制): " + adjustedKey.toString());
                    } else {
                        System.out.println("无法生成指定格式的私钥");
                    }
                } else {
                    System.out.println("私钥已经是" + formatChoice + "开头格式");
                }
            } else {
                System.out.println("无效选择，请输入 K 或 L");
            }
        }
    }

    /**
     * 调整私钥以获得指定的WIF开头格式
     */
    private static BigInteger adjustPrivateKeyFormat(BigInteger originalKey, boolean wantKStart) {
        // 通过微调私钥来改变公钥Y坐标的奇偶性
        // 注意：这种方法保持私钥在有效范围内

        int maxAttempts = 1000;
        for (int i = 1; i <= maxAttempts; i++) {
            // 尝试在原私钥基础上进行小的调整
            BigInteger[] adjustments = {
                    originalKey.add(BigInteger.valueOf(i)),
                    originalKey.subtract(BigInteger.valueOf(i)),
                    originalKey.xor(BigInteger.valueOf(i)),
                    originalKey.add(BigInteger.valueOf(i).shiftLeft(16))
            };

            for (BigInteger adjustedKey : adjustments) {
                // 确保调整后的私钥在有效范围内
                if (isValidPrivateKey(adjustedKey)) {
                    try {
                        if (isKStart(adjustedKey) == wantKStart) {
                            System.out.println("经过 " + i + " 次尝试找到目标格式");
                            return adjustedKey;
                        }
                    } catch (Exception e) {
                        // 忽略计算错误，继续尝试
                        continue;
                    }
                }
            }
        }

        return null;
    }

    /**
     * 验证私钥是否在有效范围内
     */
    private static boolean isValidPrivateKey(BigInteger key) {
        return key.compareTo(BigInteger.ONE) >= 0 &&
                key.compareTo(MAX_PRIVATE_KEY) <= 0;
    }

    /**
     * 判断私钥是否对应K开头的WIF格式
     */
    private static boolean isKStart(BigInteger privateKey) {
        ECPoint publicKeyPoint = CURVE_PARAMS.getG().multiply(privateKey).normalize();
        BigInteger pubKeyY = publicKeyPoint.getAffineYCoord().toBigInteger();
        // Y坐标为偶数 -> K开头，奇数 -> L开头
        return pubKeyY.mod(BigInteger.valueOf(2)).equals(BigInteger.ZERO);
    }

    /**
     * 将私钥转换为WIF格式
     */
    public static String privateKeyToWIF(BigInteger privateKey, boolean compressed) {
        // 1. 将私钥转换为32字节数组
        byte[] privKeyBytes = toUnsignedByteArray(privateKey, 32);

        // 2. 创建WIF负载: 0x80 + priv32 + 0x01 (压缩格式)
        byte[] payload = new byte[34];
        payload[0] = (byte) 0x80; // 主网版本前缀
        System.arraycopy(privKeyBytes, 0, payload, 1, 32);
        payload[33] = 0x01; // 压缩标志

        // 3. 计算校验和 (双重SHA-256)
        byte[] checksum = doubleSha256(payload);

        // 4. 组合最终字节数组
        byte[] wifBytes = new byte[payload.length + 4];
        System.arraycopy(payload, 0, wifBytes, 0, payload.length);
        System.arraycopy(checksum, 0, wifBytes, payload.length, 4);

        // 5. Base58编码
        return Base58.encode(wifBytes);
    }

    /**
     * 转换为定长字节数组
     */
    private static byte[] toUnsignedByteArray(BigInteger value, int length) {
        byte[] result = new byte[length];
        byte[] raw = value.toByteArray();
        int start = (raw[0] == 0) ? 1 : 0;
        int copyLength = raw.length - start;

        if (copyLength > length) {
            throw new IllegalArgumentException("私钥太大");
        }
        System.arraycopy(raw, start, result, length - copyLength, copyLength);
        return result;
    }

    /**
     * 双重SHA-256
     */
    private static byte[] doubleSha256(byte[] data) {
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            byte[] hash1 = digest.digest(data);
            byte[] hash2 = digest.digest(hash1);
            return hash2;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Base58编码实现
     */
    public static class Base58 {
        private static final char[] ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray();
        private static final BigInteger BASE = BigInteger.valueOf(58);

        public static String encode(byte[] input) {
            BigInteger value = new BigInteger(1, input);
            StringBuilder sb = new StringBuilder();

            while (value.compareTo(BASE) >= 0) {
                BigInteger[] divmod = value.divideAndRemainder(BASE);
                sb.insert(0, ALPHABET[divmod[1].intValue()]);
                value = divmod[0];
            }
            sb.insert(0, ALPHABET[value.intValue()]);

            // 处理前导零
            for (int i = 0; i < input.length && input[i] == 0; i++) {
                sb.insert(0, ALPHABET[0]);
            }

            return sb.toString();
        }
    }
}